package com.ctsi.commons.util;

import com.ctsi.commons.conversion.ConversionException;
import com.ctsi.commons.conversion.Converter;
import com.ctsi.commons.conversion.Converters;
import com.ctsi.commons.conversion.LocalizedConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

public final class ObjectType {
	private static final Logger log = LoggerFactory.getLogger(ObjectType.class);
	public final static byte[] getClassByte(String className, ClassLoader loader) {
		String location = className.replace('.', '/').concat(".class");
		InputStream in = ClassLoader.getSystemResourceAsStream(location);
		if (in == null) {
			if (loader == null) {
				loader = Thread.currentThread().getContextClassLoader();
			}
			in = loader.getResourceAsStream(location);
		}
		if (in == null) {
			throw new RuntimeException("Resource " + location + " not found ,class is " + className);
		}
		return UtilMisc.getData(in);
	}

	public static byte[] getClassByte(Object obj, ClassLoader loader) {
		return getClassByte(obj.getClass().getName(), loader);
	}

	/**
	 * 装入类
	 * 
	 * @param className
	 *            类名称
	 * @return The requested class
	 * @throws ClassNotFoundException
	 */
	public static Class<?> loadClass(String className) throws ClassNotFoundException {

		return loadClass(className, null);
	}

	/**
	 * 只使用指定的classLoader装入类
	 * 
	 * @param className
	 *            类名称
	 * @param loader
	 *            The ClassLoader
	 * @return The requested class
	 * @throws ClassNotFoundException
	 */
	public final static Class<?> loadClass(final String className, ClassLoader loader) throws ClassNotFoundException {
		Class<?> theClass = null;

		try {

			if (loader == null) {
				loader = Thread.currentThread().getContextClassLoader();
			}
			theClass = loader.loadClass(className);

		} catch (Exception e) {

			if (theClass == null) {
				theClass = Class.forName(className, true, ObjectType.class.getClassLoader());

			}

		}

		return theClass;
	}

	public static Class<?> loadClassByThisClassLoader(String clazz) {
		ClassLoader loader = ObjectType.class.getClassLoader();
		Class<?> theClass;
		try {
			theClass = loader.loadClass(clazz);
		} catch (ClassNotFoundException e) {
			return null;
		}
		return theClass;
	}

	/**
	 * 显示classloader层次
	 * 
	 * @param cl
	 *            分析层次的类装载器
	 * @param delim
	 *            断行符
	 * @param tabText
	 *            用来设置tab空白的文本符号
	 * @param indent
	 *            该类装载器的嵌套层次(从0开始);主要为了打印美观
	 * @return
	 */
	public static String showClassLoaderHierarchy(ClassLoader cl, String delim, String tabText, int indent) {
		if (cl == null) {
			String s = "null classloader " + delim;
			ClassLoader ctxcl = Thread.currentThread().getContextClassLoader();
			s += "Context class loader=" + ctxcl + " hc=" + ctxcl.hashCode();
			return s;
		}
		String s = ""; // "ClassLoader: ";
		for (int i = 0; i < indent; i++) {
            s += tabText;
        }
		s += cl + " hc=" + cl.hashCode() + delim;
		ClassLoader parent = cl.getParent();
		return s + showClassLoaderHierarchy(parent, delim, tabText, indent + 1);
	}

	/**
	 * 返回类实例
	 * 
	 * @param className
	 *            类名称
	 * @return 类实例
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public static Object getInstance(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		Class<?> c = loadClass(className);
		Object o = c.newInstance();

		return o;
	}

	/**
	 * 测试某个类是否实现了制定接口
	 * 
	 * @param objectClass
	 *            Class<?> to test
	 * @param interfaceName
	 *            接口类
	 * @return boolean 是否实现接口
	 * @throws ClassNotFoundException
	 */
	public static boolean interfaceOf(Class<?> objectClass, String interfaceName) throws ClassNotFoundException {
		Class<?> interfaceClass = loadClass(interfaceName);

		return interfaceOf(objectClass, interfaceClass);
	}

	/**
	 * 指定对象是否实现了指定接口
	 * 
	 * @param objectClass
	 *            Class<?> to test
	 * @param interfaceObject
	 *            to test against
	 * @return boolean indicating whether interfaceObject is an interface of the obj
	 */
	public static boolean interfaceOf(Class<?> objectClass, Object interfaceObject) {
		Class<?> interfaceClass = interfaceObject.getClass();

		return interfaceOf(objectClass, interfaceClass);
	}

	/**
	 * 建立新实例
	 * 
	 * @param className
	 *            class name
	 * @param parameters
	 *            构造函数参数
	 * @return An instance of the named class
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public static Object getInstance(String className, Object[] parameters) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
		Class<?>[] sig = new Class[parameters.length];
		for (int i = 0; i < sig.length; i++) {
			sig[i] = parameters[i].getClass();
		}
		Class<?> c = loadClass(className);
		Constructor<?> con = c.getConstructor(sig);
		Object o = con.newInstance(parameters);

		return o;
	}

	public static Object getInstance(String className, Object[] parameters, Class<?>[] sig) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {

		Class<?> c = loadClass(className);
		Constructor<?> con = c.getConstructor(sig);
		Object o = con.newInstance(parameters);

		return o;
	}

	/**
	 * 判断某个对象是否是某个接口的实例
	 * 
	 * @param obj 要测试的对象
	 * @param interfaceName 接口className
	 * @return true 是 false 否
	 * @throws ClassNotFoundException
	 */
	public static boolean interfaceOf(Object obj, String interfaceName) throws ClassNotFoundException {
		Class<?> interfaceClass = loadClass(interfaceName);

		return interfaceOf(obj, interfaceClass);
	}

	/**
	 * 一个类,是否是接口类
	 * 
	 * @param className
	 * @return
	 * @throws ClassNotFoundException
	 */
	public static boolean isInterface(String className) {
		Class<?> c;
		try {
			c = loadClass(className);
		} catch (ClassNotFoundException e) {
			return false;
		}
		return c.isInterface();
	}

	/**
	 * 测试一个对象是否与另一个对象实现了同一接口
	 * 
	 * @param obj
	 *            Object to test
	 * @param interfaceObject
	 *            to test against
	 * @return boolean indicating whether interfaceObject is an interface of the obj
	 */
	public static boolean interfaceOf(Object obj, Object interfaceObject) {
		Class<?> interfaceClass = interfaceObject.getClass();

		return interfaceOf(obj, interfaceClass);
	}

	/**
	 * 是否实现了指定接口
	 * 
	 * @param obj
	 *            Object to test
	 * @param interfaceClass
	 *            Class<?> to test against
	 * @return boolean true 实现,false 没有
	 */
	public static boolean interfaceOf(Object obj, Class<?> interfaceClass) {
		Class<?> objectClass = obj.getClass();

		return interfaceOf(objectClass, interfaceClass);
	}

	/**
	 * 测试一个class是否实现了指定接口
	 * 
	 * @param objectClass
	 *            需要测试的class
	 * @param interfaceClass
	 *            接口
	 * @return boolean 实现 true,不实现 false
	 */
	public final static boolean interfaceOf(Class<?> objectClass, Class<?> interfaceClass) {
		if (objectClass.isInterface()) {
			return isOrSubOf(objectClass, interfaceClass);
		}
		while (objectClass != null) {
			Class<?>[] ifaces = objectClass.getInterfaces();

			for (int i = 0; i < ifaces.length; i++) {
				if (ifaces[i] == interfaceClass) {
                    return true;
                }
			}
			objectClass = objectClass.getSuperclass();
		}
		return false;
	}

	/**
	 * 一个类是否是另一个的子类或本身
	 * 
	 * @param objectClass
	 *            需要检查的类
	 * @param parentName
	 *            父类名称
	 * @return
	 * @throws ClassNotFoundException
	 */
	public static boolean isOrSubOf(Class<?> objectClass, String parentName) throws ClassNotFoundException {
		Class<?> parentClass = loadClass(parentName);

		return isOrSubOf(objectClass, parentClass);
	}

	/**
	 * 一个类是否另一个实例类的子类或相同
	 * 
	 * @param objectClass
	 *            需要检查的类
	 * @param parentObject
	 *            需要检查的对象
	 * @return
	 */
	public static boolean isOrSubOf(Class<?> objectClass, Object parentObject) {
		Class<?> parentClass = parentObject.getClass();

		return isOrSubOf(objectClass, parentClass);
	}

	/**
	 * 一个对象是否是一个类的子类或者本省
	 * 
	 * @param obj
	 *            需要测试的对象
	 * @param parentName
	 *            类名称
	 * @return
	 * @throws ClassNotFoundException
	 */
	public static boolean isOrSubOf(Object obj, String parentName) throws ClassNotFoundException {
		Class<?> parentClass = loadClass(parentName);

		return isOrSubOf(obj, parentClass);
	}

	/**
	 * 测试一个对象是否另一个对象的字对象
	 * 
	 * @param obj 测试对象
	 * @param parentObject
	 *            父对象
	 * @return
	 */
	public static boolean isOrSubOf(Object obj, Object parentObject) {
		Class<?> parentClass = parentObject.getClass();

		return isOrSubOf(obj, parentClass);
	}

	/**
	 * 测试一个对象是否是指定类的子类
	 * 
	 * @param obj
	 *            Object to test
	 * @param parentClass
	 *            Class<?> to test against
	 * @return
	 */
	public static boolean isOrSubOf(Object obj, Class<?> parentClass) {
		Class<?> objectClass = obj.getClass();

		return isOrSubOf(objectClass, parentClass);
	}

	/**
	 * 测试一个类是否另一个类的子类
	 * 
	 * @param objectClass
	 *            测试的类
	 * @param parentClass
	 *            Class<?> to test against
	 * @return
	 */
	public final static boolean isOrSubOf(Class<?> objectClass, Class<?> parentClass) {

		while (objectClass != null) {
			if (objectClass == parentClass) {
                return true;
            }
			objectClass = objectClass.getSuperclass();
		}
		return false;
	}

	/**
	 * 一个class是否为另外对象的类型
	 * 
	 * @param objectClass
	 *            Class<?> 需要测试的类
	 * @param typeObject
	 *            Object to 标准对象
	 * @return
	 */
	public static boolean instanceOf(Class<?> objectClass, Object typeObject) {
		Class<?> typeClass = typeObject.getClass();

		return instanceOf(objectClass, typeClass);
	}

	/**
	 * Tests if a class is a class of a sub-class of or properly implements an interface
	 * 
	 * @param objectClass
	 *            Class<?> to test
	 * @param typeName
	 *            name to test against
	 * @return
	 */
	public static boolean instanceOf(Class<?> objectClass, String typeName) {
		return instanceOf(objectClass, typeName, null);
	}

	/**
	 * 测试两个对象是否是同一类型
	 * 
	 * @param obj
	 *            测试对象
	 * @param typeObject
	 *            测试对象
	 * @return
	 */
	public static boolean instanceOf(Object obj, Object typeObject) {
		Class<?> typeClass = typeObject.getClass();

		return instanceOf(obj, typeClass);
	}

	/**
	 * 测试对象是否指定类型
	 * 
	 * @param obj
	 *            测试对象
	 * @param typeName 类型名称
	 * @return
	 */
	public static boolean instanceOf(Object obj, String typeName) {
		return instanceOf(obj, typeName, null);
	}

	/**
	 * 一个class是否是指定类型的实例
	 * 
	 * 
	 * @param objectClass
	 *            Class<?> to 需要测试的雷
	 * @param typeName
	 *            类型名称
	 * @param loader
	 * @return
	 */
	public static boolean instanceOf(Class<?> objectClass, String typeName, ClassLoader loader) {
		Class<?> infoClass;
		try {
			infoClass = loadClass(typeName, loader);
		} catch (ClassNotFoundException e) {
			throw new IllegalArgumentException(e);
		}

		if (infoClass == null) {
            throw new IllegalArgumentException("Illegal type found in info map (could not load class for specified type)");
        }

		return instanceOf(objectClass, infoClass);
	}

	/**
	 * Tests if an object is an instance of a sub-class of or properly implements an interface
	 * 
	 * @param obj
	 *            Object to test
	 * @param typeName
	 *            Object to test against
	 * @param loader
	 * @return
	 */
	public static boolean instanceOf(Object obj, String typeName, ClassLoader loader) {
		Class<?> infoClass;
		try {
			infoClass = loadClass(typeName, loader);
		} catch (ClassNotFoundException e) {
			throw new IllegalArgumentException(e);
		}

		if (infoClass == null) {
            throw new IllegalArgumentException("Illegal type found in info map (could not load class for specified type)");
        }

		return instanceOf(obj, infoClass);
	}

	/**
	 * 测试一个对象是否是一个类型 implements an interface
	 * 
	 * @param obj
	 *            Object to test
	 * @param typeClass
	 *            Class<?> to test against
	 * @return
	 */
	public static boolean instanceOf(Object obj, Class<?> typeClass) {
		if (obj == null) {
            return true;
        }
		Class<?> objectClass = obj.getClass();
		return instanceOf(objectClass, typeClass);
	}

	/**
	 * 一个class是否是指定类型
	 * 
	 * @param objectClass
	 * @param typeClass
	 * @return
	 */
	public final static boolean instanceOf(Class<?> objectClass, Class<?> typeClass) {
		if (typeClass.isInterface()) {
			return interfaceOf(objectClass, typeClass);
		} else {
			return isOrSubOf(objectClass, typeClass);
		}
	}
    private static final Map<String, String> classAlias = new HashMap<String, String>();
 

    static {
        classAlias.put("String", "java.lang.String");
        classAlias.put("Boolean", "java.lang.Boolean");
        classAlias.put("BigDecimal", "java.math.BigDecimal");
        classAlias.put("Double", "java.lang.Double");
        classAlias.put("Float", "java.lang.Float");
        classAlias.put("Long", "java.lang.Long");
        classAlias.put("Integer", "java.lang.Integer");
        classAlias.put("Short", "java.lang.Short");
        classAlias.put("Byte", "java.lang.Byte");
        classAlias.put("Character", "java.lang.Character");
        classAlias.put("Timestamp", "java.sql.Timestamp");
        classAlias.put("Time", "java.sql.Time");
        classAlias.put("Date", "java.sql.Date");
        classAlias.put("Locale", "java.util.Locale");
        classAlias.put("Collection", "java.util.Collection");
        classAlias.put("List", "java.util.List");
        classAlias.put("Set", "java.util.Set");
        classAlias.put("Map", "java.util.Map");
        classAlias.put("HashMap", "java.util.HashMap");
        classAlias.put("TimeZone", "java.util.TimeZone");

        classAlias.put("boolean", Boolean.class.getName());
        classAlias.put("short", Short.class.getName());
        classAlias.put("int", Integer.class.getName());
        classAlias.put("long", Long.class.getName());
        classAlias.put("float", Float.class.getName());
        classAlias.put("double", Double.class.getName());
        classAlias.put("byte", Byte.class.getName());
        classAlias.put("char", Character.class.getName());
    }
	private static Class<?> loadClassWithAliias(final String type) throws ClassNotFoundException{
		final String result=classAlias.get(type);
	    if(UtilValidate.isNotEmpty(result)) {
            return loadClass(result);
        }
	    return loadClass(type);
	}

	/**
	 * 转化指定对象为指定类型
	 * 
	 * @param obj
	 *            需要转化的对象
	 * @param type
	 *            转化的对象类型
	 * @param format
	 *            时间格式
	 * @param locale
	 *            可以为null ,支持本地化处理数据
	 * @param noTypeFail
	 *            不支持是否抛出异常
	 * @return
	 * @throws GeneralException
	 */
	@SuppressWarnings("unchecked")
	public final static Object simpleTypeConvert(final Object obj,  String type, final String format, TimeZone timeZone, Locale locale, final boolean noTypeFail) throws GeneralException {
        if (obj == null || UtilValidate.isEmpty(type) || "Object".equals(type) || "java.lang.Object".equals(type)) {
            return obj;
        }

        int genericsStart = type.indexOf("<");
        if (genericsStart != -1) {
            type = type.substring(0, genericsStart);
        }
        Class<?> sourceClass = obj.getClass();
        Class<?> targetClass = null;
        try {
            targetClass = loadClassWithAliias(type);
        } catch (ClassNotFoundException e) {
            throw new GeneralException("Conversion from " + sourceClass.getName() + " to " + type + " not currently supported", e);
        }
        if (sourceClass.equals(targetClass)) {
            return obj;
        }
        if (obj instanceof String && ((String) obj).length() == 0) {
            return null;
        }
        Converter converter = null;
        try {
            converter = Converters.getConverter(sourceClass, targetClass);
        } catch (ClassNotFoundException e) {}
        if (converter != null) {
            if (converter instanceof LocalizedConverter) {
                @SuppressWarnings("rawtypes")
                LocalizedConverter<Object, Object> localizedConverter = (LocalizedConverter) converter;
                if (timeZone == null) {
                    timeZone = TimeZone.getDefault();
                }
                if (locale == null) {
                    locale = Locale.getDefault();
                }
                try {
                    return localizedConverter.convert(obj, locale, timeZone, format);
                } catch (ConversionException e) {
                    log.error( "Exception thrown while converting type ",e);
                    throw new GeneralException(e.getMessage(), e);
                }
            }
            try {
                return converter.convert(targetClass,obj);
            } catch (ConversionException e) {
            	log.error( "Exception thrown while converting type  ", e);
                throw new GeneralException(e.getMessage(), e);
            }
//            catch (UnsupportedOperationException e1) {
//            	log.warn("convert error :{}",e1.toString());
//            	try {
//					return converter.convert(targetClass, obj);
//				} catch (ConversionException e) {
//	            	log.error( "Exception thrown while converting type  ", e);
//	                throw new GeneralException(e.getMessage(), e);
//				}
// 
//            }
        }
        // string 特别提示
        if (targetClass.equals(String.class)) {
        	log.warn("No special conversion available for {} to String, returning object.toString().", obj.getClass().getName()  );
            return obj.toString();
        }
        if (noTypeFail) {
            throw new GeneralException("Conversion from " + obj.getClass().getName() + " to " + type + " not currently supported");
        } else {
        	log.info("No type conversion available for {} to {}, returning original object.",  obj.getClass().getName(),targetClass.getName()  );
            return obj;
        }
	}
	public static Object simpleTypeConvert(final Object obj,  String type, final String format,   Locale locale, final boolean noTypeFail) throws GeneralException {
		return simpleTypeConvert(obj,    type,     format,null,     locale,     noTypeFail);
	}
	public static Object simpleTypeConvert(Object obj, String type, String format, Locale locale) throws GeneralException {
		return simpleTypeConvert(obj, type, format, locale, true);
	}

	public static Object simpleTypeConvert(Object obj, String type, String format) throws GeneralException {
		return simpleTypeConvert(obj, type, format, null, true);
	}

}
